home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / source.exe / POSIX / BSDPSX / SETMODE.C < prev    next >
C/C++ Source or Header  |  1992-09-17  |  11KB  |  461 lines

  1. /*
  2.  * Copyright (c) 1989 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #if defined(LIBC_SCCS) && !defined(lint)
  35. static char sccsid[] = "@(#)setmode.c    5.6 (Berkeley) 5/27/91";
  36. #endif /* LIBC_SCCS and not lint */
  37.  
  38. #ifdef _POSIX_SOURCE
  39. #include <misc.h>
  40. #endif
  41.  
  42. #ifdef _POSIX_SOURCE        //DF_DSC POSIX does not need this
  43. #else                //        only MAXPATHLEN was found there
  44.     #include <sys/param.h>  //        and it wants machine directory stuff
  45. #endif
  46.  
  47. #include <sys/stat.h>
  48. #include <sys/errno.h>
  49. #ifdef SETMODE_DEBUG
  50. #include <stdio.h>
  51. #endif
  52. #include <stdlib.h>
  53. #include <ctype.h>
  54.  
  55. #define    SET_LEN    6        /* initial # of bitcmd struct to malloc */
  56. #define    SET_LEN_INCR 4        /* # of bitcmd structs to add as needed */
  57.  
  58. struct bitcmd {
  59.     char    cmd;
  60.     char    cmd2;
  61.     mode_t    bits;
  62. };
  63.  
  64. #define    CMD2_CLR    0x01
  65. #define    CMD2_SET    0x02
  66. #define    CMD2_GBITS    0x04
  67. #define    CMD2_OBITS    0x08
  68. #define    CMD2_UBITS    0x10
  69.  
  70. /*
  71.  * Given the old mode and an array of bitcmd structures, apply the operations
  72.  * described in the bitcmd structures to the old mode, and return the new mode.
  73.  * Note that there is no '=' command; a strict assignment is just a '-' (clear
  74.  * bits) followed by a '+' (set bits).
  75.  */
  76. mode_t
  77. getmode(bbox, omode)
  78.     void *bbox;
  79.     mode_t omode;
  80. {
  81.     register struct bitcmd *set;
  82.     register mode_t newmode, value;
  83.  
  84.     set = (struct bitcmd *)bbox;
  85.     newmode = omode;
  86.     for (value = 0;; set++)
  87.         switch(set->cmd) {
  88.         /*
  89.          * When copying the user, group or other bits around, we "know"
  90.          * where the bit are in the mode so that we can do shifts to
  91.          * copy them around.  If we don't use shifts, it gets real
  92.          * grundgy with lots of single bit checks and bit sets.
  93.          */
  94.         case 'u':
  95.             value = (newmode & S_IRWXU) >> 6;
  96.             goto common;
  97.  
  98.         case 'g':
  99.             value = (newmode & S_IRWXG) >> 3;
  100.             goto common;
  101.  
  102.         case 'o':
  103.             value = newmode & S_IRWXO;
  104.         common:
  105.             if (set->cmd2 & CMD2_CLR) {
  106.                 if (set->cmd2 & CMD2_UBITS)
  107.                     newmode &= ~(S_IRWXU & set->bits);
  108.                 if (set->cmd2 & CMD2_GBITS)
  109.                     newmode &= ~(S_IRWXG & set->bits);
  110.                 if (set->cmd2 & CMD2_OBITS)
  111.                     newmode &= ~(S_IRWXO & set->bits);
  112.             }
  113.             if (set->cmd2 & CMD2_SET) {
  114.                 if (set->cmd2 & CMD2_UBITS)
  115.                     newmode |= (value<<6) & set->bits;
  116.                 if (set->cmd2 & CMD2_GBITS)
  117.                     newmode |= (value<<3) & set->bits;
  118.                 if (set->cmd2 & CMD2_OBITS)
  119.                     newmode |= value & set->bits;
  120.             }
  121.             break;
  122.  
  123.         case '+':
  124.             newmode |= set->bits;
  125.             break;
  126.  
  127.         case '-':
  128.             newmode &= ~set->bits;
  129.             break;
  130.  
  131.         case 'X':
  132.             if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
  133.                 newmode |= set->bits;
  134.             break;
  135.  
  136.         case '\0':
  137.         default:
  138. #ifdef SETMODE_DEBUG
  139.             (void)printf("getmode(, %04o) -> %04o\n",
  140.                 omode, newmode);
  141. #endif
  142.             return(newmode);
  143.         }
  144. }
  145.  
  146. #define    STANDARD_BITS    (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
  147.  
  148. static struct bitcmd *
  149. addcmd(set, op, who, oparg, mask)
  150.     struct bitcmd *set;
  151.     register int oparg, who;
  152.     register int op;
  153.     mode_t mask;
  154. {
  155.     switch (op) {
  156.     case '+':
  157.     case 'X':
  158.         set->cmd = op;
  159.         set->bits = (who ? who : mask) & oparg;
  160.         break;
  161.  
  162.     case '-':
  163.         set->cmd = '-';
  164.         set->bits = (who ? who : (S_IRWXU|S_IRWXG|S_IRWXO)) & oparg;
  165.         break;
  166.  
  167.     case '=':
  168.         set->cmd = '-';
  169.         if (!who) {
  170.             set->bits = STANDARD_BITS;
  171.             who = mask;
  172.         } else
  173.             set->bits = who;
  174.         set++;
  175.  
  176.         set->cmd = '+';
  177.         set->bits = who & oparg;
  178.         break;
  179.     case 'u':
  180.     case 'g':
  181.     case 'o':
  182.         set->cmd = op;
  183.         if (who) {
  184.             set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
  185.                     ((who & S_IRGRP) ? CMD2_GBITS : 0) |
  186.                     ((who & S_IROTH) ? CMD2_OBITS : 0);
  187.             set->bits = ~0;
  188.         } else {
  189.             set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
  190.             set->bits = mask;
  191.         }
  192.     
  193.         if (oparg == '+')
  194.             set->cmd2 |= CMD2_SET;
  195.         else if (oparg == '-')
  196.             set->cmd2 |= CMD2_CLR;
  197.         else if (oparg == '=')
  198.             set->cmd2 |= CMD2_SET|CMD2_CLR;
  199.         break;
  200.     }
  201.     return(set+1);
  202. }
  203.  
  204. #define    ADDCMD(a, b, c, d) \
  205.     if (set >= endset) { \
  206.         register struct bitcmd *newset; \
  207.         setlen += SET_LEN_INCR; \
  208.         newset = realloc(saveset, sizeof(struct bitcmd) * setlen); \
  209.         if (!saveset) \
  210.             return(NULL); \
  211.         set = newset + (set - saveset); \
  212.         saveset = newset; \
  213.         endset = newset + (setlen - 2); \
  214.     } \
  215.     set = addcmd(set, (a), (b), (c), (d))
  216.  
  217. void *
  218. setmode(p)
  219.     register char *p;
  220. {
  221.     register int perm, who;
  222.     register char op;
  223.     mode_t mask;
  224.     struct bitcmd *set, *saveset, *endset;
  225.     int permXbits, setlen;
  226.     static int compress_mode();
  227.  
  228.     /*
  229.      * Get a copy of the mask for the permissions that are mask relative.
  230.      * Flip the bits, we want what's not set.
  231.      */
  232.     (void)umask(mask = umask(0));
  233.     mask = ~mask;
  234.  
  235.     setlen = SET_LEN + 2;
  236.     
  237.     set = (struct bitcmd *)malloc((u_int)(sizeof(struct bitcmd) * setlen));
  238.     if (!set)
  239.         return(NULL);
  240.     saveset = set;
  241.     endset = set + (setlen - 2);
  242.  
  243.     /*
  244.      * If an absolute number, get it and return; disallow non-octal digits
  245.      * or illegal bits.
  246.      */
  247.     if (isdigit(*p)) {
  248.         perm = (mode_t)strtol(p, (char **)0, 8);
  249. #ifdef _POSIX_SOURCE
  250.         if (perm & ~(STANDARD_BITS)) {
  251. #else
  252.         if (perm & ~(STANDARD_BITS|S_ISTXT)) {
  253. #endif
  254.             free(saveset);
  255.             return(NULL);
  256.         }
  257.         while (*++p)
  258.             if (*p < '0' || *p > '7') {
  259.                 free(saveset);
  260.                 return(NULL);
  261.             }
  262. #ifdef _POSIX_SOURCE
  263.         ADDCMD('=', (STANDARD_BITS), perm, mask);
  264. #else
  265.         ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
  266. #endif
  267.         return((void *)saveset);
  268.     }
  269.  
  270.     if (!*p) {
  271.         free(saveset);
  272.         return(NULL);
  273.     }
  274.     /*
  275.      * Build list of structures to set/clear/copy bits as described by
  276.      * each clause of the symbolic mode.
  277.      */
  278.     for (;;) {
  279.         /* First, find out which bits might be modified. */
  280.         for (who = 0;; ++p) {
  281.             switch (*p) {
  282.             case 'a':
  283.                 who |= STANDARD_BITS;
  284.                 break;
  285.             case 'u':
  286.                 who |= S_ISUID|S_IRWXU;
  287.                 break;
  288.             case 'g':
  289.                 who |= S_ISGID|S_IRWXG;
  290.                 break;
  291.             case 'o':
  292.                 who |= S_IRWXO;
  293.                 break;
  294.             default:
  295.                 goto getop;
  296.             }
  297.         }
  298.     getop:        
  299.  
  300.         if ((op = *p++) != '+' && op != '-' && op != '=') {
  301.             free(saveset);
  302.             return(NULL);
  303.         }
  304.  
  305. #ifndef _POSIX_SOURCE
  306.         who &= ~S_ISTXT;
  307. #endif
  308.         for (perm = 0, permXbits = 0;; ++p) {
  309.             switch (*p) {
  310.             case 'r':
  311.                 perm |= S_IRUSR|S_IRGRP|S_IROTH;
  312.                 break;
  313.             case 's':
  314.                 /* If only "other" bits ignore set-id. */
  315.                 if (who & ~S_IRWXO)
  316.                     perm |= S_ISUID|S_ISGID;
  317.                 break;
  318.             case 't':
  319.                 /* If only "other" bits ignore sticky. */
  320.                 if (who & ~S_IRWXO) {
  321. #ifndef _POSIX_SOURCE
  322.                     who |= S_ISTXT;
  323.                     perm |= S_ISTXT;
  324. #endif
  325.                 }
  326.                 break;
  327.             case 'w':
  328.                 perm |= S_IWUSR|S_IWGRP|S_IWOTH;
  329.                 break;
  330.             case 'X':
  331.                 permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
  332.                 break;
  333.             case 'x':
  334.                 perm |= S_IXUSR|S_IXGRP|S_IXOTH;
  335.                 break;
  336.             case 'u':
  337.             case 'g':
  338.             case 'o':
  339.                 /*
  340.                  * When ever we hit 'u', 'g', or 'o', we have
  341.                  * to flush out any partial mode that we have,
  342.                  * and then do the copying of the mode bits.
  343.                  */
  344.                 if (perm) {
  345.                     ADDCMD(op, who, perm, mask);
  346.                     perm = 0;
  347.                 }
  348.                 if (op == '+' && permXbits) {
  349.                     ADDCMD('X', who, permXbits, mask);
  350.                     permXbits = 0;
  351.                 }
  352.                 ADDCMD(*p, who, op, mask);
  353.                 break;
  354.  
  355.             default:
  356.                 /*
  357.                  * Add any permissions that we haven't already
  358.                  * done.
  359.                  */
  360.                 if (perm) {
  361.                     ADDCMD(op, who, perm, mask);
  362.                     perm = 0;
  363.                 }
  364.                 if (permXbits) {
  365.                     ADDCMD('X', who, permXbits, mask);
  366.                     permXbits = 0;
  367.                 }
  368.                 goto apply;
  369.             }
  370.         }
  371.  
  372. apply:        if (!*p)
  373.             break;
  374.         if (*p != ',')
  375.             goto getop;
  376.         ++p;
  377.     }
  378.     set->cmd = 0;
  379. #ifdef SETMODE_DEBUG
  380.     (void)printf("Before compress_mode()\n");
  381.     dumpmode(saveset);
  382. #endif
  383.     compress_mode(saveset);
  384. #ifdef SETMODE_DEBUG
  385.     (void)printf("After compress_mode()\n");
  386.     dumpmode(saveset);
  387. #endif
  388.     return((void *)saveset);
  389. }
  390.  
  391. #ifdef SETMODE_DEBUG
  392. dumpmode(set)
  393.     register struct bitcmd *set;
  394. {
  395.     for (; set->cmd; ++set)
  396.         (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
  397.             set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
  398.             set->cmd2 & CMD2_CLR ? " CLR" : "",
  399.             set->cmd2 & CMD2_SET ? " SET" : "",
  400.             set->cmd2 & CMD2_UBITS ? " UBITS" : "",
  401.             set->cmd2 & CMD2_GBITS ? " GBITS" : "",
  402.             set->cmd2 & CMD2_OBITS ? " OBITS" : "");
  403. }
  404. #endif
  405.  
  406. /*
  407.  * Given an array of bitcmd structures, compress by compacting consecutive
  408.  * '+', '-' and 'X' commands into at most 3 commands, one of each.  The 'u',
  409.  * 'g' and 'o' commands continue to be separate.  They could probably be 
  410.  * compacted, but it's not worth the effort.
  411.  */
  412. static
  413. compress_mode(set)
  414.     register struct bitcmd *set;
  415. {
  416.     register struct bitcmd *nset;
  417.     register int setbits, clrbits, Xbits, op;
  418.  
  419.     for (nset = set;;) {
  420.         /* Copy over any 'u', 'g' and 'o' commands. */
  421.         while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
  422.             *set++ = *nset++;
  423.             if (!op)
  424.                 return;
  425.         }
  426.  
  427.         for (setbits = clrbits = Xbits = 0;; nset++) {
  428.             if ((op = nset->cmd) == '-') {
  429.                 clrbits |= nset->bits;
  430.                 setbits &= ~nset->bits;
  431.                 Xbits &= ~nset->bits;
  432.             } else if (op == '+') {
  433.                 setbits |= nset->bits;
  434.                 clrbits &= ~nset->bits;
  435.                 Xbits &= ~nset->bits;
  436.             } else if (op == 'X')
  437.                 Xbits |= nset->bits & ~setbits;
  438.             else
  439.                 break;
  440.         }
  441.         if (clrbits) {
  442.             set->cmd = '-';
  443.             set->cmd2 = 0;
  444.             set->bits = clrbits;
  445.             set++;
  446.         }
  447.         if (setbits) {
  448.             set->cmd = '+';
  449.             set->cmd2 = 0;
  450.             set->bits = setbits;
  451.             set++;
  452.         }
  453.         if (Xbits) {
  454.             set->cmd = 'X';
  455.             set->cmd2 = 0;
  456.             set->bits = Xbits;
  457.             set++;
  458.         }
  459.     }
  460. }
  461.